﻿using EFCore.BulkExtensions;
using OnlineEducation.Areas.Teacher.Models;

using OnlineEducation.Controllers;
using OnlineEducation.Data;
using OnlineEducation.Data.Entities;
using OnlineEducation.Extensions;
using OnlineEducation.Helpers;
using OnlineEducation.Helpers.JQueryTable;
using OnlineEducation.Models.JQueryTable;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NPOI.OpenXmlFormats;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace OnlineEducation.Areas.Controllers
{
    [Area("Teacher")]
    [Route("[controller]/[action]")]
    [Authorize(Roles = "SuperAdmin")]
    public class TeacherController : BaseController
    {
        private readonly ILogger _logger;
        private readonly ApplicationDbContext _context;
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly IWebHostEnvironment _environment;

        public string TEMP_TEACHER_DATA_KEY
        {
            get
            {
                return "_" + User.Identity.Name.ToUpper() + "_TEMP_TEACHER_DATA_KEY_";
            }
        }

        public TeacherController(ApplicationDbContext context, ILogger<TeacherController> logger,
              UserManager<ApplicationUser> userManager, IWebHostEnvironment environment
              )
        {
            _context = context;
            _logger = logger;
            _userManager = userManager;
            _environment = environment;
        }

        /// <summary>
        /// get all users
        /// </summary>
        /// <returns></returns>
        public IActionResult Index()
        {

            // var students = await _userManager.GetUsersInRoleAsync("Teacher");

            //var teachers = _context.ApplicationUsers.Include(n => n.UserRoles)
            //    .ThenInclude(n => n.Role)
            //    .Where(n => n.UserRoles.Any(n => n.Role.Name == "Teacher"));

            return View();

        }
        [HttpPost]
        public IActionResult GetAll(DTParameters param)
        {
            var query = _context.ApplicationUsers.Include(n => n.UserRoles).ThenInclude(n => n.Role).Where(n => n.UserRoles.Any(n => n.Role.Name == "Teacher")).AsQueryable();

            if (param.Search != null && !string.IsNullOrEmpty(param.Search.Value))
            {

                query=query.Where(n => n.Email.Contains(param.Search.Value) || n.PhoneNumber.Contains(param.Search.Value) || n.UserName.Contains(param.Search.Value)
                || n.FullName.Contains(param.Search.Value));

            }

            var newQuery = new SortHelper<OnlineEducation.Data.Entities.ApplicationUser>().Apply(query, param);

            var items = newQuery.Skip(param.Start).Take(param.Length).ToArray();

            var count = newQuery.Count();

            return Json(new DTResult<OnlineEducation.Data.Entities.ApplicationUser>
            {
                draw = param.Draw,
                data = items,
                recordsFiltered = count,
                recordsTotal = count
            });



        }

        /// <summary>
        /// get the UI of a editing user.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id?}")]
        public async Task<IActionResult> Edit(int? id)
        {
            if (!id.HasValue)
            {
                return BadRequest("id为空");

            }

            var user = await _context.Users.FindAsync(id);

            var userModel = new UserEditModel()
            {
                Email = user.Email,
                UserName = user.UserName,
                FullName = user.FullName,
                Id = user.Id,
                PhoneNumber = user.PhoneNumber,
                Gender = user.Gender,
                BirthDate = user.BirthDate,
                WeChat = user.WeChat,
                WeiBo = user.Weibo,
                QQ = user.QQ,
                Title = user.Title,
                Signature = user.Signature,
                Avatar = user.avatar,
                Intro = user.Intro,
                Remark = user.Remark,
            };

            return View(userModel);


        }

        [HttpGet("{id?}")]
        public async Task<IActionResult> View(int? id)
        {
            if (!id.HasValue)
            {
                return BadRequest("id为空");

            }

            var user = await _context.Users.FindAsync(id);

            var userModel = new UserEditModel()
            {
                Email = user.Email,
                UserName = user.UserName,
                FullName = user.FullName,
                Id = user.Id,
                PhoneNumber = user.PhoneNumber,
                Gender = user.Gender,
                BirthDate = user.BirthDate,
                WeChat = user.WeChat,
                WeiBo = user.Weibo,
                QQ = user.QQ,
                Title = user.Title,
                Signature = user.Signature,
                Avatar = user.avatar,
                Intro = user.Intro,
                Remark = user.Remark,
            };

            return View(userModel);


        }
        /// <summary>
        /// update user profile data
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> Edit([FromBody] UserEditModel data)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            try
            {
                var user = await _context.Users.FindAsync(data.Id);

                user.UserName = data.UserName;
                user.PhoneNumber = data.PhoneNumber;
                user.Email = data.Email;
                user.FullName = data.FullName;
                user.Gender = data.Gender;
                user.BirthDate = data.BirthDate;
                user.WeChat = data.WeChat;
                user.Weibo = data.WeiBo;
                user.QQ = data.QQ;
                user.Title = data.Title;
                user.Signature = data.Signature;
                user.avatar = data.Avatar;
                user.Intro = data.Intro;
                user.Remark = data.Remark;

                _context.Update(user);

                await _context.SaveChangesAsync();

                return Json(new { success = true, message = "教师更新成功." });
            }
            catch (Exception ex)
            {
                return Json(new { success = false, message = ex.Message });
            }

        }




        /// <summary>
        /// get the UI of register user
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Add()
        {
            return View();
        }

        /// <summary>
        /// register a user on backend
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]

        public async Task<IActionResult> Add([FromBody] RegisterModel data)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            try
            {

                var user = new ApplicationUser
                {
                    PhoneNumber = data.PhoneNumber,
                    UserName = data.UserName,
                    FullName = data.FullName,
                    CreatedTime = DateTime.Now,
                    Email = data.Email,
                    Gender = data.Gender,
                    BirthDate = data.BirthDate,
                    WeChat = data.WeChat,
                    Weibo = data.WeiBo,
                    QQ = data.QQ,
                    Title = data.Title,
                    Signature = data.Signature,
                    avatar = data.Avatar,
                    Intro = data.Intro,
                    Remark = data.Remark,
                };

                var result = await _userManager.CreateAsync(user, data.Password);

                if (result.Succeeded)
                {
                    var rresult = await _userManager.AddToRoleAsync(user, "Teacher");

                    if (rresult.Succeeded)
                    {
                        _logger.LogInformation("User created a new account with password.");

                        return Json(new { success = true, message = "教师新增成功." });
                    }
                    else
                    {
                        _logger.LogInformation("User role created unsucceedfully.");

                        var error = rresult.Errors.FirstOrDefault();
                        if (error != null) _logger.LogError(rresult.Errors.FirstOrDefault().Description);
                        return Json(new { success = false, message = "教师新增失败" });
                    }

                }
                else
                {
                    _logger.LogInformation("User created unsucceedfully.");

                    var error = result.Errors.FirstOrDefault();
                    if (error != null) _logger.LogError(result.Errors.FirstOrDefault().Description);

                    return Json(new { success = false, message = "教师新增失败" });
                }
            }
            catch (Exception ex)
            {
                return Json(new { success = false, message = ex.Message });
            }
        }

        /// <summary>
        /// get the UI of changing password
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id?}")]

        public IActionResult ChangePassword(int? id)
        {
            return View(new ChangePasswordModel
            {
                Id = id,
            });
        }
        /// <summary>
        /// change password
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordModel data)
        {
            var user = await _userManager.FindByIdAsync(data.Id.ToString());
            if (user == null)
            {
                // Don't reveal that the user does not exist
                return Json(new { success = false, message = "教师不存在" });
            }
            var code = await _userManager.GeneratePasswordResetTokenAsync(user);
            var result = await _userManager.ResetPasswordAsync(user, code, data.Password);
            if (result.Succeeded)
            {
                return Json(new { success = true, message = "修改密码成功" });
            }
            else
            {
                return Json(new { success = false, message = "修改密码失败" });
            }
        }

        [HttpPost("{id?}")]
        public async Task<IActionResult> Delete(int? id)
        {
            var user = await _userManager.FindByIdAsync(id.ToString());

            if (user == null)
            {
                // Don't reveal that the user does not exist
                return Json(new { success = false, message = "教师不存在" });
            }
            var result = await _userManager.DeleteAsync(user);

            if (result.Succeeded)
            {
                return Json(new { success = true, message = "删除成功" });
            }
            else
            {
                return Json(new { success = false, message = "删除失败" });
            }
        }

        [HttpPost("{id?}")]
        public async Task<IActionResult> ChangeStatus(int? id)
        {
            var user = await _userManager.FindByIdAsync(id.ToString());

            if (user == null)
            {
                // Don't reveal that the user does not exist
                return Json(new { success = false, message = "教师不存在" });
            }

            var lockout = await _userManager.IsLockedOutAsync(user);

            IdentityResult result;

            if (lockout)
            {
                result = await _userManager.SetLockoutEndDateAsync(user, DateTime.UtcNow.AddHours(-1));
            }
            else
            {
                result = await _userManager.SetLockoutEndDateAsync(user, DateTime.UtcNow.AddYears(100));
            }

            if (result.Succeeded)
            {
                return Json(new { success = true, message = "状态变更成功" });
            }
            else
            {
                return Json(new { success = false, message = "状态变更失败" });
            }
        }

        /// <summary>
        /// Ajax upload temp teacher with an excel file
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> UploadTemp()
        {
            try
            {
                var files = Request.Form.Files;


                if (files.Count == 0)
                {
                    return Json(new { success = false, message = "未发现文件" });
                }

                var file = files[0];

                if (file.Length == 0)
                {
                    return Json(new { success = false, message = "文件为空" });
                }

                string fileName = DateTime.Now.ToString("MMddHHmmssfff") + file.FileName;

                DataTable dt;

                using (var fs = new MemoryStream())
                {
                    await file.CopyToAsync(fs);

                    dt = OfficeHelper.ReadStreamToDataTable(fs);
                }

                List<UserEditModel> list = HttpContext.Session.Get<List<UserEditModel>>(TEMP_TEACHER_DATA_KEY) ?? new List<UserEditModel>();

                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    DateTime? birthDate = null;

                    bool isSucceed = DateTime.TryParse(dt.Rows[i][4].ToString(),
                        CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime date);

                    if (isSucceed)
                    {
                        birthDate = date;
                    }


                    int? gender = null;

                    if (!string.IsNullOrEmpty(dt.Rows[i][3].ToString()))
                    {

                        if (dt.Rows[i][3].ToString().Trim() == "男")
                        {
                            gender = 1;
                        }
                        else if (dt.Rows[i][3].ToString().Trim() == "女")
                        {
                            gender = 0;
                        }

                    }

                    var user = new UserEditModel
                    {
                        Id = list.Count + 1,
                        UserName = dt.Rows[i][0].ToString().Trim(),
                        FullName = dt.Rows[i][1].ToString().Trim(),
                        PhoneNumber = dt.Rows[i][2].ToString().Trim(),
                        Gender = gender,
                        BirthDate = birthDate,
                        Title = dt.Rows[i][5].ToString().Trim(),
                        Signature = dt.Rows[i][6].ToString().Trim(),
                        Intro = dt.Rows[i][7].ToString().Trim(),
                        Email = dt.Rows[i][8].ToString().Trim(),
                        WeChat = dt.Rows[i][9].ToString().Trim(),
                        Remark = dt.Rows[i][10].ToString().Trim(),
                    };

                    var context = new ValidationContext(user);
                    var results = new List<ValidationResult>();
                    var isValid = Validator.TryValidateObject(user, context, results, true);

                    var message = new StringBuilder();

                    if (!isValid)
                    {
                        foreach (var validationResult in results)
                        {
                            //validation errors
                            message.Append(validationResult.ErrorMessage).Append("&#10");
                        }
                    }

                    bool isExistSameAccount = _context.ApplicationUsers.Any(n => n.UserName == user.UserName);

                    user.HasError = !isValid;

                    user.ErrorMessage = isExistSameAccount ? message.Append("相同账号已经存在").ToString() : message.ToString();

                    list.Add(user);

                    HttpContext.Session.Set(TEMP_TEACHER_DATA_KEY, list);

                    //insert in bulk 
                    //  await _context.BulkInsertAsync<OnlineEducation.Data.Entities.ApplicationUser>(list);

                }
                //get inserted customer to display.
                //var contacts = await _context.ApplicationUsers.ToListAsync();//.Where(n => n.BatchID == guid)

                //pass html string to render it throught ajax response.
                var resultdata = await this.RenderViewToStringAsync("_TeacherList", list);

                return Json(new { success = true, message = "上传成功.", data = resultdata, count = list.Count });

            }
            catch (Exception ex)
            {
                _logger.LogError("上传文件错误：" + ex.ToString());

                return Json(new { success = false, message = ex.Message });
            }



        }

        /// <summary>
        /// get temp upload data
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetUploadTemp()
        {
            try
            {
                List<UserEditModel> list = HttpContext.Session.Get<List<UserEditModel>>(TEMP_TEACHER_DATA_KEY) ?? new List<UserEditModel>();

                //pass html string to render it throught ajax response.
                var resultdata = await this.RenderViewToStringAsync("_TeacherList", list);

                return Json(new { success = true, message = "", data = resultdata, count = list.Count() });

            }
            catch (Exception ex)
            {
                _logger.LogError("上传文件错误：" + ex.ToString());

                return Json(new { success = false, message = ex.Message });
            }



        }

        /// <summary>
        /// Deletes the upload temporary.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        [HttpPost("{id?}")]
        public async Task<IActionResult> DeleteUploadTemp(int? id)
        {
            try
            {
                if (!id.HasValue)
                {
                    return BadRequest("Id为空");
                }
                var list = HttpContext.Session.Get<List<UserEditModel>>(TEMP_TEACHER_DATA_KEY) ?? new List<UserEditModel>();

                var user = list.Where(n => n.Id == id.Value).FirstOrDefault();

                if (user != null)
                {
                    list.Remove(user);

                    HttpContext.Session.Set(TEMP_TEACHER_DATA_KEY, list);
                }
                var resultdata = await this.RenderViewToStringAsync("_TeacherList", list);

                return Json(new { success = true, message = "删除成功.", data = resultdata, count = list.Count });
            }
            catch (Exception ex)
            {
                _logger.LogError("删除错误：" + ex.ToString());

                return Json(new
                {
                    success = false,
                    message = ex.Message
                });
            }
        }

        /// <summary>
        /// Edits the upload temporary.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        [HttpGet("{id?}")]
        public IActionResult EditUploadTemp(int? id)
        {
            if (!id.HasValue)
            {
                return BadRequest("Id为空");
            }

            var list = HttpContext.Session.Get<List<UserEditModel>>(TEMP_TEACHER_DATA_KEY) ?? new List<UserEditModel>();

            var user = list.Where(n => n.Id == id.Value).FirstOrDefault();

            if (user == null) return BadRequest("Teacher为空");

            return View("UploadEdit", user);


        }


        /// <summary>
        /// Edits the upload temporary.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> EditUploadTemp([FromBody] UserEditModel data)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            try
            {

                var list = HttpContext.Session.Get<List<UserEditModel>>(TEMP_TEACHER_DATA_KEY) ?? new List<UserEditModel>();

                var user = list.Where(n => n.Id == data.Id).FirstOrDefault();

                list.Remove(user);

                list.Add(data);

                HttpContext.Session.Set(TEMP_TEACHER_DATA_KEY, list);

                var resultdata = await this.RenderViewToStringAsync("_TeacherList", list);

                return Json(new { success = true, message = "教师更新成功.", data = resultdata });
            }
            catch (Exception ex)
            {
                return Json(new { success = false, message = ex.Message });
            }

        }

        /// <summary>
        /// Uploads this instance.
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Upload()
        {
            return View();
        }
        /// <summary>
        /// Uploads this instance.
        /// </summary>
        /// <returns></returns>
        [HttpPost("{id?}")]
        public async Task<IActionResult> SubmitUploadTemp(int? id)
        {

            var list = HttpContext.Session.Get<List<UserEditModel>>(TEMP_TEACHER_DATA_KEY) ?? new List<UserEditModel>();

            if (!list.Any())
            {
                return Json(new { success = true, message = "未找到上传的教师数据", data = "", count = 0 });
            }

            var templist = new List<UserEditModel>();

            foreach (var data in list)
            {
                if (data.HasError)
                {
                    templist.Add(data);
                    continue;
                }
                var user = new ApplicationUser
                {
                    PhoneNumber = data.PhoneNumber,
                    UserName = data.UserName,
                    FullName = data.FullName,
                    CreatedTime = DateTime.Now,
                    Email = data.Email,
                    Gender = data.Gender,
                    BirthDate = data.BirthDate,
                    WeChat = data.WeChat,
                    Weibo = data.WeiBo,
                    QQ = data.QQ,
                    Title = data.Title,
                    Signature = data.Signature,
                    Intro = data.Intro,
                    Remark = data.Remark,
                };
                var result = await _userManager.CreateAsync(user, "66666666");

                if (result.Succeeded)
                {
                    var rresult = await _userManager.AddToRoleAsync(user, "Teacher");
                    if (!rresult.Succeeded)
                    {
                        try
                        {
                            var existUser = _context.ApplicationUsers.Where(n => n.UserName == user.UserName).SingleOrDefault();
                            if (existUser != null)
                            {
                                _context.ApplicationUsers.Remove(existUser);
                            }
                            await _context.SaveChangesAsync();
                            data.HasError = true;
                            data.ErrorMessage = string.Join(Environment.NewLine, rresult.Errors.Select(n => n.Description).ToArray());
                            templist.Add(data);
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex.Message, ex);
                        }

                    }
                }
                else
                {
                    data.HasError = true;
                    data.ErrorMessage = string.Join(Environment.NewLine, result.Errors.Select(n => n.Description).ToArray());
                    templist.Add(data);

                }
            }
            HttpContext.Session.Set(TEMP_TEACHER_DATA_KEY, templist);

            var resultdata = await this.RenderViewToStringAsync("_TeacherList", templist);

            return Json(new { success = true, message = templist.Count() > 0 ? "教师部分数据上传成功." : "教师数据上传成功.", data = resultdata, count = templist.Count });

        }

        /// <summary>
        /// Ajax upload avatar 
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> UploadAvatar()
        {
            try
            {
                var files = Request.Form.Files;

                string fileName = "";

                if (files.Count == 0)
                {
                    return Json(new { success = false, message = "未发现文件" });
                }

                var file = files[0];

                if (file.Length == 0)
                {
                    return Json(new { success = false, message = "文件为空" });
                }

                var extension = Path.GetExtension(file.FileName);

                var filenamewithoutExt = Path.GetFileNameWithoutExtension(file.FileName);

                fileName = filenamewithoutExt + DateTime.Now.ToString("MMddHHmmssfff") + extension;

                var filePath = Path.Combine(_environment.WebRootPath, "upload", "images", "teacher", fileName);

                using (var stream = System.IO.File.Create(filePath))
                {
                    await file.CopyToAsync(stream);

                    await stream.FlushAsync();
                }

                return Json(new { success = true, imageUrl = "/upload/images/teacher/" + fileName });


            }
            catch (Exception ex)
            {
                _logger.LogError("上传文件错误：" + ex.ToString());

                return Json(new { success = false, message = ex.Message });
            }



        }
    }
}
